﻿using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using Internal.KuiHuaBaoDian.Services.Battle.Behaviour;
using KuiHuaBaoDian.Services.Battle.Entity;
using KuiHuaBaoDian.Services.Battle.StateMachine;
using KuiHuaBaoDian.Services.Lockstep;
using UnityEngine;

namespace KuiHuaBaoDian.Services.Battle.Behaviour {

    /// <summary>
    /// 战斗行为
    /// </summary>
    public interface IBattleBehaviour : IObject {

        public interface IEntity : IBattleEntity {
        }

        /// <summary>
        /// 逻辑触发
        /// </summary>
        /// <param name="frameIndex">帧号</param>
        /// <param name="parameter">参数</param>
        IBattleBehaviourInfo LogicFrame(int frameIndex, object parameter = null);

        /// <summary>
        /// 帧触发
        /// </summary>
        /// <param name="info"></param>
        void Execute(IBattleBehaviourInfo info);

        /// <summary>
        /// 渲染
        /// </summary>
        void Update();

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="entity">实体</param>
        /// <param name="gameObject">GameObject对象</param>
        /// <param name="stateMachine">状态机</param>
        void Initialize(IEntity entity, GameObject gameObject, IBattleEntityStateMachine stateMachine);
    }

    public abstract class KHBD_BattleBehaviour : KHBD_BattleBehaviour<IBattleBehaviourInfo> {
    }

    public abstract class KHBD_BattleBehaviour<TInfo> : KHBD_BattleBehaviour<TInfo, object> where TInfo : IBattleBehaviourInfo {

        protected abstract TInfo LogicFrame();

        [Obsolete]
#pragma warning disable CS0809 // 过时成员重写未过时成员
        protected sealed override TInfo LogicFrame(object parameter) => LogicFrame();
#pragma warning restore CS0809 // 过时成员重写未过时成员
    }

    public abstract class KHBD_BattleBehaviour<TInfo, TParameter> : KHBD_Object, IBattleBehaviour where TInfo : IBattleBehaviourInfo where TParameter : class {

        private record UpdateInfo(float StartFrameTime, float TotalTime);

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        protected static F64 Delta(F64 @in) => @in * LockstepService.Instance.FrameLength;

        protected GameObject GameObject { get; private set; }

        protected IBattleEntityStateMachine StateMachine { get; private set; }

        private IBattleBehaviour.IEntity m_Entity;
        protected IBattleBehaviour.IEntity Entity => m_Entity;

        //private Queue<UpdateInfo> m_UpdateInfoQueue = new();

        private Queue<IBattleBehaviourInfo> m_BehaviourInfoQueue = new();

        protected TInfo CurrentBehaviourInfo => (TInfo)m_BehaviourInfoQueue.Peek();

        public void Initialize(IBattleBehaviour.IEntity entity, GameObject gameObject, IBattleEntityStateMachine stateMachine) {
            GameObject = gameObject;
            StateMachine = stateMachine;
            m_Entity = entity;
            Initialize();
        }

        protected abstract void Initialize();

        protected override void Dispose() {
            GameObject = null;
            StateMachine = null;
            m_Entity = null;
            //m_UpdateInfoQueue = null;
            m_BehaviourInfoQueue = null;
        }

        //private int m_LogicFrameIndex = int.MinValue;
        //private int m_LogicFrameCount = 0;

        protected abstract TInfo LogicFrame(TParameter parameter);
        IBattleBehaviourInfo IBattleBehaviour.LogicFrame(int frameIndex, object parameter) {
            //if (m_LogicFrameIndex == int.MinValue) {
            //    m_LogicFrameIndex = frameIndex;
            //}
            //m_LogicFrameCount++;
            var behaviourInfo = LogicFrame(parameter == null ? null : (TParameter)parameter);
            if (behaviourInfo is IBattleBehaviourInfoInternal @internal) {
                @internal.FrameIndex = frameIndex;
            }
            return behaviourInfo;
        }

        protected abstract void Execute(TInfo info);
        void IBattleBehaviour.Execute(IBattleBehaviourInfo info) {
            Execute((TInfo)info);
            m_BehaviourInfoQueue.Enqueue(info);
        }

        protected abstract void Update(TInfo info, float interpolation);
        void IBattleBehaviour.Update() {
            while (m_BehaviourInfoQueue.Count > 0) {
                var behaviourInfo = m_BehaviourInfoQueue.Peek();
                var frameIndex = (behaviourInfo as IBattleBehaviourInfoInternal).FrameIndex;
                var elapsedTime = LockstepService.Instance.AccumulatedTime - frameIndex * LockstepService.Instance.FrameLengthRaw;
                var interpolation = elapsedTime / LockstepService.Instance.FrameLengthRaw;
                //UnityEngine.Debug.Log($"{nameof(interpolation)}:{interpolation},{LockstepService.Instance.AccumulatedTime},{nameof(frameIndex)}:{frameIndex}");
                if (interpolation >= 0f) {
                    Update((TInfo)behaviourInfo, Mathf.Min(interpolation, 1f));
                }
                if (interpolation >= 1f) {
                    m_BehaviourInfoQueue.Dequeue();
                    continue;
                }
                break;
            }
        }
    }
}
